#pragma once

#include "Common.hpp"
#include "ThreadCache.hpp"

// 申请对象
static void* ConcurrentAlloc(size_t bytes)
{
	void* ptr = nullptr;
	if (bytes > MAX_BYTES)  // 大于 256 kb
	{
		// ① 大于 256 kb ,小于 1MB 的,还是在 SpanList 的管辖内
		// ② 大于 1MB 的,直接向 堆申请，不经过 PageCache


		size_t alignSize = SizeClass::RoundUp(bytes);
		// 计算应该分配的页数
		// 
		//PageCache::GetInstanse()
		Span* span;

		{
			// 去 PageCache 申请内存需要加锁
			std::unique_lock<std::mutex> lock(PageCache::GetInstanse()._mutex);
			span = PageCache::GetInstanse().newSpan(alignSize >> PAGE_SHIFT);  // 获取相应的页数

			// 存储相应的大小
			span->_objSize = bytes;
		}

		ptr = (void*)(span->_pageId << PAGE_SHIFT);		// 重新计算得到指针
	}
	else
	{
		if (pTLSThreadCache == nullptr)
		{
			// 如果为空，则说明当前线程第一次初始化，为其分配 ThreadCache 对象

			
			//std::unique_lock<std::mutex> lock(PageCache::GetInstanse()._mutex);
				// 设置为 static 对象，保证每个线程内全局只有一个，防止每次调用函数都生成一个
			static ObjectPool<ThreadCache> _threadcachepool((2 * sizeof size_t + sizeof(void*)) * NFREELIST + 32);  // 预留 32 byte 的空间
			
						//pTLSThreadCache = new ThreadCache;
			pTLSThreadCache = _threadcachepool.New();
		}

		ptr = pTLSThreadCache->Allocate(bytes);
	}
	return ptr;

}

template<typename T = void*>
static T* NewAlloc(size_t bytes = sizeof T)
{
	void* ptr = ConcurrentAlloc(bytes);
	*(T*)ptr = T();
	return (T*)ptr;
}


// 释放对象
static void ConcurrentFree(void* ptr)  // 这里在归还内存时，暂时需要给出大小
{
	size_t bytes = PageCache::GetInstanse().MapObjectToSpan(ptr)->_objSize;

	if (bytes > MAX_BYTES)
	{
		// 即大于 128 页，大于 1MB
		// 找到对应的 Span
		Span* span = PageCache::GetInstanse().MapObjectToSpan(ptr);

		{
			std::unique_lock<std::mutex> lock(PageCache::GetInstanse()._mutex);
			PageCache::GetInstanse().ReleaseSpanToPageCache(span);
		}
	}
	else
	{
		assert(pTLSThreadCache);
		pTLSThreadCache->Deallocate(ptr, bytes);
	}
}
	